#pragma once

#include "../for_hiboost/headers.HiBoost.h"

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include "common.h"
#include "ImageEx.h"
#include "OrNode.h"
#include "AndNodeModel.h"
#include "LeafNodeModel.h"
#include "Timer.h"

using	namespace	std;

class COrNode;

class CAndNode
{
	////typedef	struct tagStateInfo
	////{
	////	vector<BasicInstInfoType>	centers;
	////	double						sumOri,	sumLen;
	////	double						Ori, Scale;
	////	int							count;
	////} StateInfoType;

	public:
		CAndNode(void);
		~CAndNode(void);

	public:
		int							ModelID;
		int							Level;

		bool						parseInfo;
		bool						createInfo;
		bool						fNeedMakeInstTree;
		bool						fNeedRefreshMRFScore;

		vector<int>					children;
		vector<int>					fullIndex;
		vector<int>					CenterIndex;
		vector<int>					ConstrainIndex;
		vector<NodeInstanceType>	instances;
		vector<NodeInstanceType>	fullInst;

		int							NodeType;
		int							leafIndex;					// for nodes whose child is leaf node
		bool						FillMissing;				// fill missing nodes or not

		// Inference
		double						BottomUpTimeCost;
		int							ActiveThres;

		//For loopy inference
		vector<NodeInstanceType>	SearchConstrain;

	public:
		double						MaxOriDiff, MaxScaleDiff;
		double						MaxOri, MinScale, MaxScale;
		double						Variance;
		int							BoundarySize;
		int							MaxFullInstCount;
		int							MaxInstCount, MinInstCount;

	// Learning
	public:
		vector<double>				TripletScore_;

		double						BaseAppearanceScore;
		//vector<double>				LeafFeature_;

		vector<double>				ArcScaleScore_, ArcRotScore_;

	public:	// useless ??
		//int							InstCount;
		double						InstScore_;
		//int							MaxLevel;


	// Methods

	public:
		bool InputFromStream(istream& inStream);
		void OutputToStream(ostream& outStream) const;

	public:
		int		BottomUpSearch(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, const char* ccpPN_ParseLog);

	public:
		int		DrawInstanceNode(CHiBoostImageEntity &entity, string strImageFileName);

	public:
		// Leaf node
		int		MakeLeafNodeInstance_BottomUp(ModelTreeType &model, CHiBoostImageEntity &entity);

		// Or node
		int		MakeAndNodeInstance_BottomUp(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, int ChildID, NodeInstanceType &instance);
		int		MakeInstanceLeafInfo(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &Instance);
		int		AddInstance_BottomUp(ModelTreeType &model, NodeInstanceType &instance);

		int		AddInstanceArcCenters(ModelTreeType &model, NodeInstanceType &instance);
		int		MakeInstanceLeafNodes(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &instance, vector<BasicNodePairType> &LeafNodes);
		int		MakeHierarchyInstanceCenter(NodeInstanceType &Instance);
		int		MakeInstanceRotateAndScaleByLeafNodes(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &instance);
		int		MakeInstanceRotateAndScale(ModelTreeType &model, NodeInstanceType &instance);
		bool	UnderGeoConstrain_BottomUp(ModelTreeType &model, NodeInstanceType &instance, int CurrID);
		bool	UnderGeoConstrain_BottomUp(ModelTreeType &model, NodeInstanceType &instance);

		// Calculate the Score of an instance
		
		void	MakeBaseAppearanceScore(CHiBoostImageEntity &entity, NodeInstanceType &Instance);
		int		MakeMRFScore(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &Instance);
		//int		MakeMRFScore(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &Instance, bool fComputeAppearanceScore);

		int		MakeTripletFeature(
			const CAndNodeModel::TripletType& triplet, const ModelTreeType& model,
			BasicInstInfoType &node1, BasicInstInfoType &node2, BasicInstInfoType &node3,
			vector<double> &feature, BasicInstInfoType &node);
		double	MakeTripletScore(ModelTreeType &model, int TripletID, vector<double> &feature);

		// NMS
		int		RemoveReduntantInstance_BottomUp(ModelTreeType &model);
		int		FreeFullInstanceSet();

		// Fill in
		void	RefreshMRFScore(ModelTreeType &model, InstanceTreeType& tree);

		int		RemakeInstTree_NoEntity(ModelTreeType &model, InstanceTreeType &tree);
		int		MakeInstTree(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, bool fComputeAppearanceScore);

		int		FillInMissChildNode_BottomUp(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &Instance);
		int		FillInMissTree_BottomUp(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &Instance);
		int		FillInInstInTree(InstanceTreeType &tree, InstanceTreeType &tree_fillin, int InstID);

		int		MakeMissLeafNodes(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, BasicInstInfoType &center, vector<BasicNodePairType> &LeafNodes);
		int		MakeInstFromLeafNodes(ModelTreeType &model, InstanceTreeType &CurrTree, InstanceTreeType &MissTree, CHiBoostImageEntity &entity, vector<BasicNodePairType> &LeafNodes, int OrNodeID);

	public:
		static double OriDiff(double ori1, double ori2);
		static bool InstanceSimilar(ModelTreeType &model, int NodeIndex, NodeInstanceType &p1, NodeInstanceType &p2);

		int		DrawInstance(ModelTreeType &model, CHiBoostImageEntity &entity, NodeInstanceType &instance, string strImageFileName);
		int		DrawSearchConstrains(ModelTreeType &model, CHiBoostImageEntity &entity, string strImageFileName);

		int		ReCompositeAndNodeInst_MakeTree_NoEntity(ModelTreeType &model, InstanceTreeType &tree, int ChildID, NodeInstanceType &Instance);
		int		CompositeAndNodeInst_MakeTree(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity, int ChildID, NodeInstanceType &Instance, bool fComputeAppearanceScore);

	// Initialization

	public:
		void	CreateNaiveModelFromNodes(ModelTreeType &model, InstanceTreeType &tree);
		void	CreateAndNodeInstance(ModelTreeType &model, InstanceTreeType &tree, int ChildID, NodeInstanceType &instance, vector<BasicNodePairType> &LeafNodes);
		void	CreateUpdateAndNodeInstance(ModelTreeType &model, InstanceTreeType &tree, NodeInstanceType &instance, vector<BasicNodePairType> &LeafNodes);
		void	CreateUpdateAndNodeModel(ModelTreeType &model, InstanceTreeType &tree);
		void	_MergeChildInstance_BottomUp(NodeInstanceType &Instance, vector<BasicNodePairType> &LeafNodes, int ChildID);
		void	_RemoveChildInstance_BottomUp(vector<BasicNodePairType> &LeafNodes, int ChildID);

	// Learning
	public:
		double	AnalyseScore(
			vector<double>& DstScoreList_SubTree, vector<double>& DstScoreList_PerNode,
			CHiBoostImageEntity &entity, InstanceTreeType &tree, int InstID
			);
		int		UpdateParameters(
			ModelTreeType &model, ModelTreeType &NewModel,
			CHiBoostImageEntity &entity,
			InstanceTreeType &tree, InstanceTreeType &ground_tree,
			int InstID,
			double UpdatingWeight);

	//Loopy Inference
		int		AddSearchCenterIndex(ModelTreeType &model, InstanceTreeType &tree, ArcModelType &Rule, bool NxtStatus);
		int		SetNodeSearchStatus(ModelTreeType &model, InstanceTreeType &tree);
		int		MakeSearchConstrain(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity);
};